#include "unp.h"

void hello(const char* msg) {
	printf("%s\n", msg);
}

void exitWithError(const char * msg, int exitCode) {
	perror(msg);
	exit(exitCode);
}

int Socket(int family, int type, int protocol) {
	int n;
	if ((n = socket(family, type, protocol)) < 0) {
		exitWithError("ERROR socket", 1);
	}

	return n;
}

void Connect(int sockfd, SA * serv_addr, int addrlen) {
	if ( connect(sockfd, serv_addr, addrlen) < 0) {
		exitWithError("ERROR connect", 1);
	}
}


void Listen(int sockfd, int backlog) {
	if (listen(sockfd, backlog) < 0)
		exitWithError("ERROR listen", 1);
}

void Bind(int sockfd, SA * serv_addr, int addrlen) {
	if ( bind(sockfd, serv_addr, addrlen) < 0) {
		exitWithError("ERROR bind", 1);
	}
}

int Accept(int sockfd, SA * serv_addr, int * addrlen) {
	int n;
	if ((n = accept(sockfd, serv_addr, addrlen)) < 0) {
		exitWithError("ERROR accept", 1);
	}
	return n;
}

int Write(int sockfd, const char *vptr, size_t n) {
	size_t nleft = n;
	ssize_t nwritten;
	const char *ptr =  vptr;

	while (nleft > 0) {
		nwritten = write(sockfd, ptr, nleft);
		if (nwritten <= 0) {
			if (errno = EINTR) nwritten = 0;
			else exitWithError("ERROR write", 1);
		}
		nleft -= nwritten;
		ptr += nwritten;
	}
	return n;
}

int Read(int sockfd, char * vptr, size_t n) {
	ssize_t nread;
	bzero(vptr, n);

again:
	nread = read(sockfd, vptr, n);
	if (nread < 0 ) {
		if (errno == EINTR) {
			nread = 0;
			goto again;
		}
		else exitWithError("ERROR read", 1);
	}
	return nread;
}


void Close(int sockfd) {
	if (close(sockfd) < 0) {
		exitWithError("ERROR close", 1);
	}
}

int Fork() {
	int pid = fork();
	if (pid < 0) {
		exitWithError("ERROR fork", 1);
	}
	return pid;
}

void Inet_pton(int af, const char *src, void *dest) {
	if (inet_pton(af, src, dest) == 0) {
		exitWithError("ERROR inet_pton", 1);
	}
}


char *Fgets(char *s, int size, FILE *stream) {
	bzero(s, size);
	char* ptr = fgets(s, size, stream);
	if (ptr == NULL) {
		// TODO
		return ptr;
	}
	return ptr;
}

int Fputs(char *s, FILE *stream) {
	int n = fputs(s, stream);
	if (n == EOF) {
		exitWithError("ERROR fputs", 1);
	}
	return n;
}

void* Signal(int signo, void*(*func)(int)) {
	struct sigaction act, oact;
	act.sa_handler = func;
	sigemptyset(&act.sa_mask);
	act.sa_flags = 0;
	if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
		act.sa_flags |= SA_INTERRUPT;
#endif
	} else {
#ifdef SA_RESTART
		act.sa_flags |= SA_RESTART;
#endif
	}

	if (sigaction(signo, &act, &oact) < 0) {
		return SIG_ERR;
	}
	return oact.sa_handler;
}


void sig_chld(int signo) {
	// Warning: Calling standard I/O functions in a signal handler is not recommended
	pid_t pid;
	int stat;
	// pid = wait(&stat);
	// printf("child %d terminated\n", pid);
	while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
		printf("child %d terminated\n", pid);
	}
	return;
}
